package com.weibopay.gf;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.weibopay.gf.model.request.ApplyCrossBorderEntryRequest;
import com.weibopay.gf.model.request.QueryBalanceRequest;
import com.weibopay.gf.service.ApiService;
import com.weibopay.gf.support.ApiUrl;
import com.weibopay.gf.support.ServiceType;
import com.weibopay.gf.util.SignUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 开放平台API Demo
 * RSA公私钥生成请参考测试包中：{@code com.weibopay.gf.testing.RSAKeyGenerate}
 * 接口文档请参考：新浪跨境支付-开放平台API接口-v1.0(版本号随着API迭代会变更).docx
 */
public class OpenPlatformApiDemo {
    public static void main(String[] args) throws Exception {
        //开放平台业务接口调用
//        String responseBody = ServiceType.ApplyCrossBorderEntry.getApiService().apiRequest(applyCrossBorderEntryRequest());
//        System.out.println("接口Response:" + JSON.toJSONString(JSON.parseObject(responseBody), true));

        //余额查询
//        String responseBody = ServiceType.QueryBalance.getApiService().apiRequest(tradeOrderQuery());
//        System.out.println("接口Response:" + JSON.toJSONString(JSON.parseObject(responseBody), true));

        //生成文件摘要
//        System.out.println(fileDigest());

//        fileDigest();
        fileUpload();
        //签名验签
//        String notifyParam = "{\"response_code\":\"1000\",\"partner_id\":\"1631802429603808370\",\"response_message\":\"成功\",\"file_name\":\"file_1782406514400795648.xlsx\",\"sign\":\"Q0smrItXpto3nW+FBoSNqflqkvBeLoGuGvWpJ2lpnUjNwpS2NeeSteuK+YaK/BgV3fW6BE4tVb2grhhNxwiyKEQhssMlgDIH5HnpS/oIvklr4UvG5P1uJlAb8Gajf2hljF8IasyERzbzefeIP5uRoBXGXBlJT3ATJlSLIrEtVkE=\",\"response_time\":\"20211117144614\",\"sign_type\":\"RSA\",\"version\":\"1.0\"}";
//        boolean result = SignUtils.init(ApiUrl.platformPublicKey).verifySign(JSON.parseObject(notifyParam));
//        System.out.println("验签结果:" + result);
    }

    /**
     * 示例：商户入境申请
     * 其他业务接口类似，按照业务参数传输即可
     */
    static String applyCrossBorderEntryRequest() {
        ApplyCrossBorderEntryRequest request = ApplyCrossBorderEntryRequest.builder()
                .merchant_order_no("123456789")
                .cross_border_type("CORSSBORDER_ENTRY")
                .poundage_undertake("")
                .cross_border_currency("CNY")
                .cross_border_amount("1.00")
                .trade_desc("交易附言")
                .trade_type("交易类型参照Excel表格")
                .trade_child_type("交易子类型参照Excel表格")
                .trade_data_url("23435435435345.xlsx")
                .trade_data_name("交易还原数据.xlsx")
                .trade_material_url("34545654654767.xlsx")
                .trade_material_name("交易还原材料.xlsx")
                .payer_account_no("2345345645743254345")
                .payer_name("测试账户")
                .country("CN")
                .build();

        request.setVersion("1.0");
        request.setRequest_time(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        request.setPartner_id("合作者身份ID");
//        request.setNotify_url("异步通知地址");
        request.setMemo("订单备注");


        return JSON.toJSONString(request);
    }

    /**
     * 余额查询
     */
    static String tradeOrderQuery() {
        QueryBalanceRequest request = QueryBalanceRequest.builder()
                .cross_border_currency("CNY")
                .build();

        request.setVersion("1.0");
        request.setRequest_time(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        request.setPartner_id("1631802429603808370");

        return JSON.toJSONString(request);
    }

    /**
     * 文件摘要
     * 场景：上传文件时需要上传文件摘要参数
     */
    static String fileDigest() throws FileNotFoundException {
        InputStream stream = ResourceUtil.getStreamSafe("test.xlsx");
        if (Objects.isNull(stream)) {
            throw new FileNotFoundException("文件不存在");
        }
        return SecureUtil.md5(stream);
    }

    /**
     * 文件上传
     */
    static String fileUpload() throws Exception {

        String file_digest = fileDigest();
//        String request_time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        JSONObject jsonBody = new JSONObject();
        //请求参数拼接
        jsonBody.put("file_digest", file_digest);
        jsonBody.put("partner_id", "1631802429603808370");
        jsonBody.put("request_time", "20211117132844");
        jsonBody.put("version", "1.0");
        String signParam = getSignParam(jsonBody);
        //生成签名
        Sign signType = getPlatformSign("RSA");
        byte[] signByte = signType.sign(signParam.getBytes(StandardCharsets.UTF_8.name()));
        String sign = Base64.encode(signByte);
        System.out.println("生成签名：" + sign);
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        //以下参数具体值需商户自己生成，这里仅做示例
        Resource fileSystemResource = new FileSystemResource("test.xlsx");
        byte[] bytes = IoUtil.readBytes(fileSystemResource.getInputStream());
        map.add("file_digest", file_digest);
        map.add("file", Base64.encode(bytes));
        map.add("partner_id", "1631802429603808370");
        map.add("version", "1.0");
        map.add("request_time", "20211117132844");
        map.add("sign", sign);
        map.add("sign_type", "RSA");
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity(map, headers);
        //发送请求，设置请求返回数据格式为String
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(ApiUrl.fileServiceUrl + "/upload/file", request, String.class);
        return JSONObject.toJSONString(responseEntity);
    }


    /**
     * 无需加入签名的参数
     */
    public static final List<String> NO_SIGN_PARAM = Arrays.asList("sign", "sign_type");
    /**
     * HTTP请求基本参数
     */
    public static final List<String> BASIC_PARAM = Arrays.asList("sign", "sign_type", "partner_id", "version", "request_time");

    /**
     * 组装签名参数
     *
     * @param jsonBody 所需要签名的参数
     * @return 签名后的值
     */
    public static String getSignParam(Map<String, Object> jsonBody) {
        //剔除非签名参数
        Map<String, Object> signParam = new HashMap<>();
        jsonBody.forEach((k, v) -> {
            if (!NO_SIGN_PARAM.contains(k)) {
                signParam.put(k, v);
            }
        });
        //拼接参数用户校验签名
        return MapUtil.sortJoin(signParam, "&", "=", true);
    }


    /**
     * 获取签名工具类
     *
     * @param signType 签名类型，目前支持RSA和RSA2
     * @return 返回签名类
     */
    public static Sign getPlatformSign(String signType) {
        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwrzbQhbSO38H3GnzWnRz5W+wpXcXYoMuPgTtEnW1w4PCYk4z6/kUOBr9icoPPJ6rmOC5QKppBXmKQwGFru9WJH2Zd/xYTSdnS8qSoeYOb4mlY4Vli0IcR7dqO58ivVueXgl6zOJZ0Va5x9n3Bj2S4DYbosADs11SqjbVi5I+PZQIDAQAB";
        String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALCvNtCFtI7fwfcafNadHPlb7Cldxdigy4+BO0SdbXDg8JiTjPr+RQ4Gv2Jyg88nquY4LlAqmkFeYpDAYWu71YkfZl3/FhNJ2dLypKh5g5viaVjhWWLQhxHt2o7nyK9W55eCXrM4lnRVrnH2fcGPZLgNhuiwAOzXVKqNtWLkj49lAgMBAAECgYAIcviOFDbENlMSPAQIR08hZZHvkHprl5Tkceuhpl2bbkZTJYsyXYJz30K7tHo1J9J2W+1rC/6AbcEM5wZBnqPhbFQ6BbKJD9uxY+uaeOAKlXJFWU3nNu2dC2kXts4jXM5UidN08WemRlk1AYgM8eHyIZhBovQxhx4CRxMffr4ZqQJBAO41zgx2GYvqSfn3LTGTFIetkeAD8E0XKvyLjv/BSm+mOLEGD0XG36JBjrAgJ/BKWKdspo6LN9vAvPbaf8+h/WcCQQC94SLSuOi4J/V69yEP3KRQC2/M9AlmIFfpIQA9z1g/LFlp7wp5YQGBUC//ilMNJCx3D7O8rLkfjpYZHAZhawFTAkEAzVHDECqbSmXe7X2HjrtfbrLEkXnTnh7iBlukHf3U0vdK1gqLD3GjQI+RFW4h/pOWZnjX9vU4aElwlrUuhSDy8QJAfMTLVRwcD6ZyL/LjzsB1WAOr20kgQ/NM0OvWdMcifaBuwKVKhKexjX9bitch66ixbyrqODhnDM1s4+L+blUZ8QJBANH1mUdmhY83adzaO5noaUChK+Wi2REGIXOgV9YvuDx7oWoAivKaWBAm0adn+BlICV0PmaXcsK7/NbYVTlWvYcw=";
        switch (signType) {
            case "RSA":
                return SecureUtil.sign(SignAlgorithm.SHA1withRSA, privateKey, publicKey);
            case "RSA2":
                return SecureUtil.sign(SignAlgorithm.SHA256withRSA, publicKey, privateKey);
            default:
                return null;
        }
    }


}
